package com.hopedove.workshop.ui.dialog

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.CheckBox
import android.widget.CompoundButton
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.DialogFragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.hopedove.utils.ToastUtil
import com.hopedove.workshop.R
import com.hopedove.workshop.databinding.WorkshopMaterialListDialogBinding
import com.hopedove.workshop.databinding.WorkshopMaterialListItemBinding

class ListSelectionDialog(multiSelect: Boolean = true, val title: String = "") : DialogFragment() {

    private lateinit var binding: WorkshopMaterialListDialogBinding
    private val mAdapter = ListAdapter()
    var getSelectedItem: ((List<Int>) -> Unit)? = null

    private var selection: Selection = if (multiSelect) MultiSelection() else SingleSelection()

    // 必选选择一项才能点确认
    var mustSelectedToConfirm = false

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = DataBindingUtil.inflate(
            inflater,
            R.layout.workshop_material_list_dialog,
            container,
            false
        )

        initViews()

        return binding.root
    }

    fun setData(list: List<ListItem>) {
        mAdapter.setData(list)
        selection.setData(mAdapter.data)
    }

    private fun initViews() {
        if (title.isNotEmpty()) {
            binding.tvTitle.text = title
        }
        binding.rlList.apply {
            layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
            adapter = mAdapter
        }

        if (selection is MultiSelection) {
            binding.cbSelectAll.visibility = View.VISIBLE
            binding.cbSelectAll.isEnabled = true
            binding.cbSelectAll.setOnCheckedChangeListener(selectAllListener)
        } else {
            binding.cbSelectAll.visibility = View.INVISIBLE
            binding.cbSelectAll.isEnabled = false
        }

        binding.btnCancel.setOnClickListener { dismissAllowingStateLoss() }
        binding.btnConfirm.setOnClickListener {
            // 没有数据，可以直接 dismiss
            if (mAdapter.data.isEmpty()) {
                dismissAllowingStateLoss()
            }

            // 如果有数据，需要检查是否设置了必须选择一项的条件约束
            val selectedIndexes = mAdapter.getSelectedItemIndex()
            if (mustSelectedToConfirm && selectedIndexes.isEmpty()) {
                ToastUtil.longToast(context, "请至少选择一项")
            } else {
                getSelectedItem?.invoke(selectedIndexes)
                dismissAllowingStateLoss()
            }
        }

    }

    private val selectAllListener = CompoundButton.OnCheckedChangeListener { _, isChecked ->
        updateToggleCheckbox(isChecked, null)
    }

    private fun updateToggleCheckbox(toggle: Boolean?, isAllChecked: Boolean?) {
        toggle?.let {
            mAdapter.toggleAllSelection(it)
        }

        isAllChecked?.let { checkStatus ->
            // 由 列表项发起的状态变化，先取消监听
            // 否则会导致不必要的回调
            binding.cbSelectAll.apply {
                setOnCheckedChangeListener(null)
                isChecked = checkStatus
                setOnCheckedChangeListener(selectAllListener)
            }
        }
    }

    private inner class ListAdapter : RecyclerView.Adapter<VH>() {
        val data = mutableListOf<ListItem>()

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
            val binding: WorkshopMaterialListItemBinding =
                DataBindingUtil.inflate(
                    LayoutInflater.from(context),
                    R.layout.workshop_material_list_item,
                    parent,
                    false
                )
            return VH(binding)
        }

        override fun onBindViewHolder(holder: VH, position: Int) {
            holder.render(data, position)
        }

        override fun getItemCount(): Int = data.size

        fun setData(list: List<ListItem>) {
            data.clear()
            data.addAll(list)
            notifyDataSetChanged()
        }

        fun toggleAllSelection(select: Boolean) {
            val selectionOp = selection
            if (selectionOp is MultiSelection) {
                selectionOp.checkAll(select)
                notifyDataSetChanged()
            }
        }

        fun getSelectedItemIndex(): List<Int> {
            val indexs = mutableListOf<Int>()
            data.forEachIndexed { index, item ->
                if (item.checked) indexs.add(index)
            }
            return indexs
        }

    }

    private inner class VH(val binding: WorkshopMaterialListItemBinding) :
        RecyclerView.ViewHolder(binding.root) {

        fun render(data: List<ListItem>, position: Int) {
            binding.item = data[position]

            binding.cbSelect.setOnClickListener { v ->
                val cb = v as CheckBox
                if (cb.isChecked) {
                    selection.check(position)
                } else {
                    selection.uncheck(position)
                }
                updateToggleCheckbox(null, selection.isAllChecked())
            }
        }
    }


    private abstract class Selection(protected val data: MutableList<ListItem> = mutableListOf()) {
        fun setData(list: List<ListItem>) {
            data.clear()
            data.addAll(list)
        }

        abstract fun check(index: Int)

        fun uncheck(index: Int) {
            data[index].checked = false
        }

        fun checkedNumber() = data.count { it.checked }

        fun isAllChecked() = checkedNumber() == data.size
    }

    private class SingleSelection : Selection() {
        override fun check(index: Int) {
            data.forEachIndexed { idx, item -> item.checked = idx == index }
        }
    }

    private class MultiSelection() : Selection() {
        override fun check(index: Int) {
            data[index].checked = true
        }

        fun checkAll(select: Boolean) {
            data.forEach { it.checked = select }
        }
    }

    data class ListItem(
        var checked: Boolean = false,
        val text: String
    )

}








